Advanced Data Journalism Final Project

Data from:

https://data.mo.gov/Health/Missouri-Cooling-Centers-Sites/ks2s-yguy

https://ephtracking.cdc.gov/DataExplorer/?c=35&i=88&m=-1

https://public.tableau.com/app/profile/samantha2462/viz/shared/437ZHKXJZ

https://moboscoc.org/resources/data/point-in-time-count-reports/

Step 1: Load libraries

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.4.0      ✔ purrr   1.0.1 
✔ tibble  3.1.8      ✔ dplyr   1.0.10
✔ tidyr   1.3.0      ✔ stringr 1.5.0 
✔ readr   2.1.3      ✔ forcats 0.5.2 ── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(ggplot2)
library(dplyr)
library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(maps)

Attaching package: ‘maps’

The following object is masked from ‘package:purrr’:

    map
library(leaflet)
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(ggiraph)
library(plotly)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
#Animation Libraries
#I opted not to animate data because none of the data I collected seemed well-suited for animating over time. I did, however, include the code I used to try and animate the bar graph at the end of the assignment.

library(gganimate)
library(sp)
library(viridis)
Loading required package: viridisLite

Attaching package: ‘viridis’

The following object is masked from ‘package:maps’:

    unemp
library(htmltools)
library(gapminder)
library(gifski)
library(png)
library(tmap)

Step 2: Load data

We will be using three data sets. One contains the coordinates and details for cooling centers serving Missouri and another contains heat-related hospitalizations over the last several years. The last one contains information about people experiencing homelessness at a specific point in time from the U.S. Department of Housing and Urban Development.

coolingcenters <- read_csv("Final Project/Missouri_Cooling_Centers_Sites.csv")
Rows: 538 Columns: 11── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): FACILITY, ADDRESS, CITY, COUNTY, PHONE, HOURS OF OPERATION, Location, ADA-Accessible, TRANSPORTATION, state
dbl  (1): ZIPCODE
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
heathospitalizations <- read_csv("Final Project/heatrate.csv")
New names:Rows: 602 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (3): StateFIPS, State, Data Comment
dbl (2): Year, Value
lgl (1): ...6
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
hud_mo <- read_csv("Final Project/HUDmo.csv")
Rows: 101 Columns: 4── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): County, Measure Names
dbl (2): Measure Values, Total
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Step 3: Clean data

Clean & organize cooling centers data.

Our data needs to be properly — and specifically — formatted so it can be easily visualized.

#First, I'm separating the latitude and longitude into separate boxes. 
coolingcentersclean <- coolingcenters %>% 
  separate(Location, sep=", ", into=c("latitude", "longitude"))

#I'm also cleaning up these boxes by removing the parentheses from them.
coolingcentersclean <- coolingcentersclean %>%
 mutate(lat = str_replace(latitude, "[(]", ""))

coolingcentersclean <- coolingcentersclean %>%
 mutate(long = str_replace(longitude, "[)]", ""))

#I'm going to change the state abbreviations to their names so it will be easier to combine with the states data.
coolingcentersclean <- coolingcentersclean %>% mutate(region = case_when(
  grepl("MO", state, ignore.case=T) ~ "missouri",
  grepl("IL", state, ignore.case=T) ~ "illinois",
  grepl("KS", state, ignore.case=T) ~ "kansas"))

#I'm going to remove the improperly formatting latitude and longitude from the dataset. 
coolingcentersclean <- subset (coolingcentersclean, select = -latitude)
coolingcentersclean <- subset (coolingcentersclean, select = -longitude)

#We'll need our coordinates to be numbers so we can plot them.
coolingcentersclean$lat <- as.numeric(coolingcentersclean$lat)
coolingcentersclean$long <- as.numeric(coolingcentersclean$long)

#Lastly, I'll be cleaning the names with janitor. 
coolingcentersclean <- clean_names(coolingcentersclean)

Clean & organize heat data

#This dataset is relatively clean, so I'm just going to clean the names and then remove the column at the end.
heathospitalizations <- clean_names(heathospitalizations)
heathosptializations <- tolower(heathospitalizations$state)

heathospitalizations <- subset (heathospitalizations, select = -x6)

Clean & organize HUD data

#This dataset is relatively clean, so I'm just going to clean the names and rename the unsheltered column for the sake of ease.
hud_mo <- clean_names(hud_mo)
hud_mo <- hud_mo %>% rename(unsheltered_total = measure_values)

Step 4: Load map data

states <- map_data("state") %>% filter(region=="missouri" | region == "illinois" | region == "kansas")

statescounties <- map_data("county")

mocounties <- map_data("county") %>% filter(region ==  "missouri")

Step 5: Create custom interactive dot map

By using county-level data from the maps package and plotly, we can create our own custom interactive dot map.

dotmap_ <- ggplot(statescounties, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "#F8F9F9", color = "darkgray", linewidth=.1) +
  geom_point(data=coolingcentersclean, aes(group = NULL, text = paste("Location:", facility)),   alpha=.5, size=.7, color="#EE9253") +   
  coord_fixed(1.3) +
  theme_void() +
  labs(title="Cooling Centers in Missouri in 2022", caption = "Data from data.mo.gov") + theme_void() 
Warning: Ignoring unknown aesthetics: text
dotmap <- ggplotly(dotmap_, tooltip = "text")

Step 6: Create interactive dot map with leaflet

Leaflet is a simpler way to plot data interactively.

interactivedotmap <- leaflet() %>% 
    addProviderTiles(providers$CartoDB.Positron) %>%
    addCircleMarkers(
    data = coolingcentersclean,
    color = "#EE9253",
    opacity = 0.5,
    radius = 1,
    ~long, ~lat, popup = ~htmlEscape(facility))

Step 7: Create an interactive bar graph

Similar to how we created a custom interactive dot map, we can do the same for bar graphs.

#I'm going to create a tooltip first to make the bar graph interactive. 
heathospitalizations <- heathospitalizations %>% mutate(
    tooltip_text = paste0(year, " - ", value, "%"))

colors <- c("National Average" = "red")


#Now, I'm going to use ggplot to create the bar graph.
bar_graph_ <- heathospitalizations %>% 
  filter(state=="Missouri") %>% 
  ggplot(aes(x=year, y=value, tooltip = tooltip_text, data_id = state)) + 
  theme_minimal() +
  geom_col_interactive(width=.7, size = 0.2, fill="#EE9253") + 
  geom_hline_interactive(aes(yintercept = 2.010133, tooltip = "National Average: 2.010133%", linetype="National Average")) +
        scale_linetype_manual(name = "", values = "solid") +
        scale_size_manual(aes(size=.05)) +
theme(axis.text=element_text(size = 7), axis.title=element_text(size=7), title=element_text(size=7), legend.position = "bottom", legend.text = element_text(size=5), legend.title = element_text(size=7)) +
labs(title = "Percentage of heat-related illness hospitalizations in Missouri per 100k people 2000-2020", subtitle = "Data from CDC") +
ylab("Percentage of heat hospitalizations") +
xlab("Year")

#Girafe will let us make the graph interactive.
bar_graph <- girafe(ggobj = bar_graph_, width_svg = 5, height_svg = 3, gg_hline1)

Step 8: Create an interactive chloropleth graph

hud_mo <- hud_mo %>% 
 mutate(county = str_replace(county, '\\.', ''))

hud_states <- 
  hud_mo %>% 
  mutate(county = str_to_lower(county)) %>% 
  right_join(mocounties, by = c("county" = "subregion"))

hud_states <- hud_states %>% mutate(
    tooltip_text = paste0(county, " - ", unsheltered_total))

chloro_map_ <-ggplot(hud_states, aes(x = long, y = lat, group = group, fill = unsheltered_total, tooltip = tooltip_text, data_id = county)) +
  theme_void() +
  geom_polygon_interactive(colour = "white", linewidth = .1) +
  coord_fixed(1.3) +
  scale_fill_continuous(low = '#F9E79F',high = '#D4AC0D', n.breaks=10, name="Total unsheltered individuals") +
  labs(title = "Total people who are unsheltered in Missouri counties — 2019",subtitle = "Data from CDC") +
  theme(title=element_text(size=7), legend.position = "right", legend.text = element_text(size=5), legend.title = element_text(size=7))

chloro_map <- girafe(ggobj = chloro_map_, width_svg = 5, height_svg = 3)

Step 9: Do some basic analysis

coolingcentersclean %>% 
  filter(transportation == "Yes")
#No centers provide transportation

coolingcentersclean %>% 
  filter(ada_accessible == "No")
#All centers are ADA accessible

coolingcentersclean %>% 
  group_by(county) %>% 
  count(county) %>% 
  arrange(desc(n))
#Jackson County has the most cooling centers followed by St. Louis county and then Madison

coolingcentersclean %>% 
  filter(county == "Boone")
#Boone County has 6 cooling centers

coolingcentersclean %>% 
  filter(grepl("sun", hours_of_operation, ignore.case=T))
#58 centers are open on Sundays

heathospitalizations %>% 
  arrange(desc(value))
#California had the highest heat-related hospitalization rate in 2020; Missouri had the sixth highest rate in 2011 at 7.6.

heathospitalizations %>% 
  filter(state=="Missouri") %>% 
  arrange(desc(value))
#Missouri had its highest number of heat-related hospitalizations in 2011

heathospitalizations %>% 
  summarise(average = mean(value))
#The average percentage of heat-related illness hospitalizations from 2000 to 2021 using availble data was 2.010133%.

heathospitalizations %>% 
  group_by(state) %>% 
  summarise(average = mean(value)) %>% 
  arrange(desc(average))
#Missouri has the second highest rate of the data reported. 

Story Package

Important statistics and data analysis to include in the story:

In the last two decades, Missouri ranks in the top ten out of reporting states for the highest rate of heat-related illnesses per 100,000 people. In 2011, the rate in Missouri reached 7.6%, ranking it number 6 behind Arizona.

Missouri currently reports 538 cooling centers. 58 of those cooling centers are open on Sundays.

Graphs to include in the story:

dotmap
interactivedotmap

Methodology:

Three data sets were used and analyzed in this story package.

The first data set documents the locations of cooling centers in the state of Missouri. This data is from 2022 and was collected from data.mo.gov. It is reported by the Missouri Department of Health & Senior Services. The data only includes cooling centers that are reported to the Missouri Department of Health & Senior Services, and therefore may exclude some cooling centers.

The second data set documents the percent of age-adjusted heat-related illness hospitalizations in the United States per 100,000 people. It was accessed from the Centers for Disease Control. It is important to note that all states report data every year. In my analysis, I included all states’ data. In creating the bar chart, however, I included filtered for data from only Missouri, for all years available from 2000 to 2021.

The third data set documents the number of unsheltered individuals experiencing homelessness in 2019, which is the most recent data available for download. It comes from the Missouri Balance of State Continua of Care, as required by the Missouri Department of Health & Senior Services. Some counties are not reported in the data. In the chart, these counties are listed with data as “N/A”.

Animation code:

This code may take a while to load, and requires rendering packages to show the animation.

animatedgraph <- heathospitalizations %>% 
  filter(state=="Missouri" | state=="Arizona") %>% 
  ggplot(aes(x=state, y=value, fill=state)) + 
  theme_minimal() +
  theme(axis.text=element_text(size = 7), axis.title=element_text(size=7), title=element_text(size=7), legend.position = "bottom", legend.text = element_text(size=5), legend.title = element_text(size=7)) +
labs(title = "Percentage of heat-related illness hospitalizations in Missouri and Arizona per 100k people 2000-2020", subtitle = "Data from CDC") +
ylab("Percentage of heat hospitalizations") +
xlab("Year")

 animatedgraph + geom_bar(stat='identity') +
  transition_states(
    year,
    transition_length = 20,
    state_length = 1) +
  ease_aes('sine-in-out') +
     transition_time(year) +
labs(title = "Year: {frame_time}")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyAqKkFkdmFuY2VkIERhdGEgSm91cm5hbGlzbSBGaW5hbCBQcm9qZWN0KioKCkRhdGEgZnJvbToKCjxodHRwczovL2RhdGEubW8uZ292L0hlYWx0aC9NaXNzb3VyaS1Db29saW5nLUNlbnRlcnMtU2l0ZXMva3Mycy15Z3V5PgoKPGh0dHBzOi8vZXBodHJhY2tpbmcuY2RjLmdvdi9EYXRhRXhwbG9yZXIvP2M9MzUmaT04OCZtPS0xPgoKPGh0dHBzOi8vcHVibGljLnRhYmxlYXUuY29tL2FwcC9wcm9maWxlL3NhbWFudGhhMjQ2Mi92aXovc2hhcmVkLzQzN1pIS1hKWj4KCjxodHRwczovL21vYm9zY29jLm9yZy9yZXNvdXJjZXMvZGF0YS9wb2ludC1pbi10aW1lLWNvdW50LXJlcG9ydHMvPgoKIyMjIFN0ZXAgMTogTG9hZCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShnZ2lyYXBoKQpsaWJyYXJ5KHBsb3RseSkKCiNBbmltYXRpb24gTGlicmFyaWVzCiNJIG9wdGVkIG5vdCB0byBhbmltYXRlIGRhdGEgYmVjYXVzZSBub25lIG9mIHRoZSBkYXRhIEkgY29sbGVjdGVkIHNlZW1lZCB3ZWxsLXN1aXRlZCBmb3IgYW5pbWF0aW5nIG92ZXIgdGltZS4gSSBkaWQsIGhvd2V2ZXIsIGluY2x1ZGUgdGhlIGNvZGUgSSB1c2VkIHRvIHRyeSBhbmQgYW5pbWF0ZSB0aGUgYmFyIGdyYXBoIGF0IHRoZSBlbmQgb2YgdGhlIGFzc2lnbm1lbnQuCgpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeShzcCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGh0bWx0b29scykKbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkoZ2lmc2tpKQpsaWJyYXJ5KHBuZykKbGlicmFyeSh0bWFwKQoKCmBgYAoKIyMjIFN0ZXAgMjogTG9hZCBkYXRhCgpXZSB3aWxsIGJlIHVzaW5nIHRocmVlIGRhdGEgc2V0cy4gT25lIGNvbnRhaW5zIHRoZSBjb29yZGluYXRlcyBhbmQgZGV0YWlscyBmb3IgY29vbGluZyBjZW50ZXJzIHNlcnZpbmcgTWlzc291cmkgYW5kIGFub3RoZXIgY29udGFpbnMgaGVhdC1yZWxhdGVkIGhvc3BpdGFsaXphdGlvbnMgb3ZlciB0aGUgbGFzdCBzZXZlcmFsIHllYXJzLiBUaGUgbGFzdCBvbmUgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgcGVvcGxlIGV4cGVyaWVuY2luZyBob21lbGVzc25lc3MgYXQgYSBzcGVjaWZpYyBwb2ludCBpbiB0aW1lIGZyb20gdGhlIFUuUy4gRGVwYXJ0bWVudCBvZiBIb3VzaW5nIGFuZCBVcmJhbiBEZXZlbG9wbWVudC4KCmBgYHtyfQpjb29saW5nY2VudGVycyA8LSByZWFkX2NzdigiRmluYWwgUHJvamVjdC9NaXNzb3VyaV9Db29saW5nX0NlbnRlcnNfU2l0ZXMuY3N2IikKCmhlYXRob3NwaXRhbGl6YXRpb25zIDwtIHJlYWRfY3N2KCJGaW5hbCBQcm9qZWN0L2hlYXRyYXRlLmNzdiIpCgpodWRfbW8gPC0gcmVhZF9jc3YoIkZpbmFsIFByb2plY3QvSFVEbW8uY3N2IikKYGBgCgojIyMgU3RlcCAzOiBDbGVhbiBkYXRhCgpDbGVhbiAmIG9yZ2FuaXplIGNvb2xpbmcgY2VudGVycyBkYXRhLgoKT3VyIGRhdGEgbmVlZHMgdG8gYmUgcHJvcGVybHkgLS0tIGFuZCBzcGVjaWZpY2FsbHkgLS0tIGZvcm1hdHRlZCBzbyBpdCBjYW4gYmUgZWFzaWx5IHZpc3VhbGl6ZWQuCgpgYGB7cn0KI0ZpcnN0LCBJJ20gc2VwYXJhdGluZyB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBpbnRvIHNlcGFyYXRlIGJveGVzLiAKY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjb29saW5nY2VudGVycyAlPiUgCiAgc2VwYXJhdGUoTG9jYXRpb24sIHNlcD0iLCAiLCBpbnRvPWMoImxhdGl0dWRlIiwgImxvbmdpdHVkZSIpKQoKI0knbSBhbHNvIGNsZWFuaW5nIHVwIHRoZXNlIGJveGVzIGJ5IHJlbW92aW5nIHRoZSBwYXJlbnRoZXNlcyBmcm9tIHRoZW0uCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUKIG11dGF0ZShsYXQgPSBzdHJfcmVwbGFjZShsYXRpdHVkZSwgIlsoXSIsICIiKSkKCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUKIG11dGF0ZShsb25nID0gc3RyX3JlcGxhY2UobG9uZ2l0dWRlLCAiWyldIiwgIiIpKQoKI0knbSBnb2luZyB0byBjaGFuZ2UgdGhlIHN0YXRlIGFiYnJldmlhdGlvbnMgdG8gdGhlaXIgbmFtZXMgc28gaXQgd2lsbCBiZSBlYXNpZXIgdG8gY29tYmluZSB3aXRoIHRoZSBzdGF0ZXMgZGF0YS4KY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjb29saW5nY2VudGVyc2NsZWFuICU+JSBtdXRhdGUocmVnaW9uID0gY2FzZV93aGVuKAogIGdyZXBsKCJNTyIsIHN0YXRlLCBpZ25vcmUuY2FzZT1UKSB+ICJtaXNzb3VyaSIsCiAgZ3JlcGwoIklMIiwgc3RhdGUsIGlnbm9yZS5jYXNlPVQpIH4gImlsbGlub2lzIiwKICBncmVwbCgiS1MiLCBzdGF0ZSwgaWdub3JlLmNhc2U9VCkgfiAia2Fuc2FzIikpCgojSSdtIGdvaW5nIHRvIHJlbW92ZSB0aGUgaW1wcm9wZXJseSBmb3JtYXR0aW5nIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgZnJvbSB0aGUgZGF0YXNldC4gCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gc3Vic2V0IChjb29saW5nY2VudGVyc2NsZWFuLCBzZWxlY3QgPSAtbGF0aXR1ZGUpCmNvb2xpbmdjZW50ZXJzY2xlYW4gPC0gc3Vic2V0IChjb29saW5nY2VudGVyc2NsZWFuLCBzZWxlY3QgPSAtbG9uZ2l0dWRlKQoKI1dlJ2xsIG5lZWQgb3VyIGNvb3JkaW5hdGVzIHRvIGJlIG51bWJlcnMgc28gd2UgY2FuIHBsb3QgdGhlbS4KY29vbGluZ2NlbnRlcnNjbGVhbiRsYXQgPC0gYXMubnVtZXJpYyhjb29saW5nY2VudGVyc2NsZWFuJGxhdCkKY29vbGluZ2NlbnRlcnNjbGVhbiRsb25nIDwtIGFzLm51bWVyaWMoY29vbGluZ2NlbnRlcnNjbGVhbiRsb25nKQoKI0xhc3RseSwgSSdsbCBiZSBjbGVhbmluZyB0aGUgbmFtZXMgd2l0aCBqYW5pdG9yLiAKY29vbGluZ2NlbnRlcnNjbGVhbiA8LSBjbGVhbl9uYW1lcyhjb29saW5nY2VudGVyc2NsZWFuKQpgYGAKCkNsZWFuICYgb3JnYW5pemUgaGVhdCBkYXRhCgpgYGB7cn0KI1RoaXMgZGF0YXNldCBpcyByZWxhdGl2ZWx5IGNsZWFuLCBzbyBJJ20ganVzdCBnb2luZyB0byBjbGVhbiB0aGUgbmFtZXMgYW5kIHRoZW4gcmVtb3ZlIHRoZSBjb2x1bW4gYXQgdGhlIGVuZC4KaGVhdGhvc3BpdGFsaXphdGlvbnMgPC0gY2xlYW5fbmFtZXMoaGVhdGhvc3BpdGFsaXphdGlvbnMpCmhlYXRob3NwdGlhbGl6YXRpb25zIDwtIHRvbG93ZXIoaGVhdGhvc3BpdGFsaXphdGlvbnMkc3RhdGUpCgpoZWF0aG9zcGl0YWxpemF0aW9ucyA8LSBzdWJzZXQgKGhlYXRob3NwaXRhbGl6YXRpb25zLCBzZWxlY3QgPSAteDYpCmBgYAoKQ2xlYW4gJiBvcmdhbml6ZSBIVUQgZGF0YQoKYGBge3J9CiNUaGlzIGRhdGFzZXQgaXMgcmVsYXRpdmVseSBjbGVhbiwgc28gSSdtIGp1c3QgZ29pbmcgdG8gY2xlYW4gdGhlIG5hbWVzIGFuZCByZW5hbWUgdGhlIHVuc2hlbHRlcmVkIGNvbHVtbiBmb3IgdGhlIHNha2Ugb2YgZWFzZS4KaHVkX21vIDwtIGNsZWFuX25hbWVzKGh1ZF9tbykKaHVkX21vIDwtIGh1ZF9tbyAlPiUgcmVuYW1lKHVuc2hlbHRlcmVkX3RvdGFsID0gbWVhc3VyZV92YWx1ZXMpCmBgYAoKIyMjIFN0ZXAgNDogTG9hZCBtYXAgZGF0YQoKYGBge3J9CnN0YXRlcyA8LSBtYXBfZGF0YSgic3RhdGUiKSAlPiUgZmlsdGVyKHJlZ2lvbj09Im1pc3NvdXJpIiB8IHJlZ2lvbiA9PSAiaWxsaW5vaXMiIHwgcmVnaW9uID09ICJrYW5zYXMiKQoKc3RhdGVzY291bnRpZXMgPC0gbWFwX2RhdGEoImNvdW50eSIpCgptb2NvdW50aWVzIDwtIG1hcF9kYXRhKCJjb3VudHkiKSAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAgIm1pc3NvdXJpIikKYGBgCgojIyMgU3RlcCA1OiBDcmVhdGUgY3VzdG9tIGludGVyYWN0aXZlIGRvdCBtYXAKCkJ5IHVzaW5nIGNvdW50eS1sZXZlbCBkYXRhIGZyb20gdGhlIG1hcHMgcGFja2FnZSBhbmQgcGxvdGx5LCB3ZSBjYW4gY3JlYXRlIG91ciBvd24gY3VzdG9tIGludGVyYWN0aXZlIGRvdCBtYXAuCgpgYGB7cn0KZG90bWFwXyA8LSBnZ3Bsb3Qoc3RhdGVzY291bnRpZXMsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCkpICsKICBnZW9tX3BvbHlnb24oZmlsbCA9ICIjRjhGOUY5IiwgY29sb3IgPSAiZGFya2dyYXkiLCBsaW5ld2lkdGg9LjEpICsKICBnZW9tX3BvaW50KGRhdGE9Y29vbGluZ2NlbnRlcnNjbGVhbiwgYWVzKGdyb3VwID0gTlVMTCwgdGV4dCA9IHBhc3RlKCJMb2NhdGlvbjoiLCBmYWNpbGl0eSkpLCAgIGFscGhhPS41LCBzaXplPS43LCBjb2xvcj0iI0VFOTI1MyIpICsgICAKICBjb29yZF9maXhlZCgxLjMpICsKICB0aGVtZV92b2lkKCkgKwogIGxhYnModGl0bGU9IkNvb2xpbmcgQ2VudGVycyBpbiBNaXNzb3VyaSBpbiAyMDIyIiwgY2FwdGlvbiA9ICJEYXRhIGZyb20gZGF0YS5tby5nb3YiKSArIHRoZW1lX3ZvaWQoKSAKCmRvdG1hcCA8LSBnZ3Bsb3RseShkb3RtYXBfLCB0b29sdGlwID0gInRleHQiKQoKYGBgCgojIyMgU3RlcCA2OiBDcmVhdGUgaW50ZXJhY3RpdmUgZG90IG1hcCB3aXRoIGxlYWZsZXQKCkxlYWZsZXQgaXMgYSBzaW1wbGVyIHdheSB0byBwbG90IGRhdGEgaW50ZXJhY3RpdmVseS4KCmBgYHtyfQppbnRlcmFjdGl2ZWRvdG1hcCA8LSBsZWFmbGV0KCkgJT4lIAogICAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lCiAgICBhZGRDaXJjbGVNYXJrZXJzKAogICAgZGF0YSA9IGNvb2xpbmdjZW50ZXJzY2xlYW4sCiAgICBjb2xvciA9ICIjRUU5MjUzIiwKICAgIG9wYWNpdHkgPSAwLjUsCiAgICByYWRpdXMgPSAxLAogICAgfmxvbmcsIH5sYXQsIHBvcHVwID0gfmh0bWxFc2NhcGUoZmFjaWxpdHkpKQpgYGAKCiMjIyBTdGVwIDc6IENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBiYXIgZ3JhcGgKClNpbWlsYXIgdG8gaG93IHdlIGNyZWF0ZWQgYSBjdXN0b20gaW50ZXJhY3RpdmUgZG90IG1hcCwgd2UgY2FuIGRvIHRoZSBzYW1lIGZvciBiYXIgZ3JhcGhzLgoKYGBge3J9CiNJJ20gZ29pbmcgdG8gY3JlYXRlIGEgdG9vbHRpcCBmaXJzdCB0byBtYWtlIHRoZSBiYXIgZ3JhcGggaW50ZXJhY3RpdmUuIApoZWF0aG9zcGl0YWxpemF0aW9ucyA8LSBoZWF0aG9zcGl0YWxpemF0aW9ucyAlPiUgbXV0YXRlKAogICAgdG9vbHRpcF90ZXh0ID0gcGFzdGUwKHllYXIsICIgLSAiLCB2YWx1ZSwgIiUiKSkKCmNvbG9ycyA8LSBjKCJOYXRpb25hbCBBdmVyYWdlIiA9ICJyZWQiKQoKCiNOb3csIEknbSBnb2luZyB0byB1c2UgZ2dwbG90IHRvIGNyZWF0ZSB0aGUgYmFyIGdyYXBoLgpiYXJfZ3JhcGhfIDwtIGhlYXRob3NwaXRhbGl6YXRpb25zICU+JSAKICBmaWx0ZXIoc3RhdGU9PSJNaXNzb3VyaSIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgdG9vbHRpcCA9IHRvb2x0aXBfdGV4dCwgZGF0YV9pZCA9IHN0YXRlKSkgKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIGdlb21fY29sX2ludGVyYWN0aXZlKHdpZHRoPS43LCBzaXplID0gMC4yLCBmaWxsPSIjRUU5MjUzIikgKyAKICBnZW9tX2hsaW5lX2ludGVyYWN0aXZlKGFlcyh5aW50ZXJjZXB0ID0gMi4wMTAxMzMsIHRvb2x0aXAgPSAiTmF0aW9uYWwgQXZlcmFnZTogMi4wMTAxMzMlIiwgbGluZXR5cGU9Ik5hdGlvbmFsIEF2ZXJhZ2UiKSkgKwogICAgICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9ICJzb2xpZCIpICsKICAgICAgICBzY2FsZV9zaXplX21hbnVhbChhZXMoc2l6ZT0uMDUpKSArCnRoZW1lKGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZSA9IDcpLCBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCB0aXRsZT1lbGVtZW50X3RleHQoc2l6ZT03KSwgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpKSArCmxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBoZWF0LXJlbGF0ZWQgaWxsbmVzcyBob3NwaXRhbGl6YXRpb25zIGluIE1pc3NvdXJpIHBlciAxMDBrIHBlb3BsZSAyMDAwLTIwMjAiLCBzdWJ0aXRsZSA9ICJEYXRhIGZyb20gQ0RDIikgKwp5bGFiKCJQZXJjZW50YWdlIG9mIGhlYXQgaG9zcGl0YWxpemF0aW9ucyIpICsKeGxhYigiWWVhciIpCgojR2lyYWZlIHdpbGwgbGV0IHVzIG1ha2UgdGhlIGdyYXBoIGludGVyYWN0aXZlLgpiYXJfZ3JhcGggPC0gZ2lyYWZlKGdnb2JqID0gYmFyX2dyYXBoXywgd2lkdGhfc3ZnID0gNSwgaGVpZ2h0X3N2ZyA9IDMsIGdnX2hsaW5lMSkKCmBgYAoKIyMjIFN0ZXAgODogQ3JlYXRlIGFuIGludGVyYWN0aXZlIGNobG9yb3BsZXRoIGdyYXBoCgpgYGB7cn0KaHVkX21vIDwtIGh1ZF9tbyAlPiUgCiBtdXRhdGUoY291bnR5ID0gc3RyX3JlcGxhY2UoY291bnR5LCAnXFwuJywgJycpKQoKaHVkX3N0YXRlcyA8LSAKICBodWRfbW8gJT4lIAogIG11dGF0ZShjb3VudHkgPSBzdHJfdG9fbG93ZXIoY291bnR5KSkgJT4lIAogIHJpZ2h0X2pvaW4obW9jb3VudGllcywgYnkgPSBjKCJjb3VudHkiID0gInN1YnJlZ2lvbiIpKQoKaHVkX3N0YXRlcyA8LSBodWRfc3RhdGVzICU+JSBtdXRhdGUoCiAgICB0b29sdGlwX3RleHQgPSBwYXN0ZTAoY291bnR5LCAiIC0gIiwgdW5zaGVsdGVyZWRfdG90YWwpKQoKY2hsb3JvX21hcF8gPC1nZ3Bsb3QoaHVkX3N0YXRlcywgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gdW5zaGVsdGVyZWRfdG90YWwsIHRvb2x0aXAgPSB0b29sdGlwX3RleHQsIGRhdGFfaWQgPSBjb3VudHkpKSArCiAgdGhlbWVfdm9pZCgpICsKICBnZW9tX3BvbHlnb25faW50ZXJhY3RpdmUoY29sb3VyID0gIndoaXRlIiwgbGluZXdpZHRoID0gLjEpICsKICBjb29yZF9maXhlZCgxLjMpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gJyNGOUU3OUYnLGhpZ2ggPSAnI0Q0QUMwRCcsIG4uYnJlYWtzPTEwLCBuYW1lPSJUb3RhbCB1bnNoZWx0ZXJlZCBpbmRpdmlkdWFscyIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIHBlb3BsZSB3aG8gYXJlIHVuc2hlbHRlcmVkIGluIE1pc3NvdXJpIGNvdW50aWVzIOKAlCAyMDE5IixzdWJ0aXRsZSA9ICJEYXRhIGZyb20gQ0RDIikgKwogIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTUpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT03KSkKCmNobG9yb19tYXAgPC0gZ2lyYWZlKGdnb2JqID0gY2hsb3JvX21hcF8sIHdpZHRoX3N2ZyA9IDUsIGhlaWdodF9zdmcgPSAzKQoKYGBgCgojIyMgU3RlcCA5OiBEbyBzb21lIGJhc2ljIGFuYWx5c2lzCgpgYGB7cn0KY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUgCiAgZmlsdGVyKHRyYW5zcG9ydGF0aW9uID09ICJZZXMiKQojTm8gY2VudGVycyBwcm92aWRlIHRyYW5zcG9ydGF0aW9uCgpjb29saW5nY2VudGVyc2NsZWFuICU+JSAKICBmaWx0ZXIoYWRhX2FjY2Vzc2libGUgPT0gIk5vIikKI0FsbCBjZW50ZXJzIGFyZSBBREEgYWNjZXNzaWJsZQoKY29vbGluZ2NlbnRlcnNjbGVhbiAlPiUgCiAgZ3JvdXBfYnkoY291bnR5KSAlPiUgCiAgY291bnQoY291bnR5KSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKQojSmFja3NvbiBDb3VudHkgaGFzIHRoZSBtb3N0IGNvb2xpbmcgY2VudGVycyBmb2xsb3dlZCBieSBTdC4gTG91aXMgY291bnR5IGFuZCB0aGVuIE1hZGlzb24KCmNvb2xpbmdjZW50ZXJzY2xlYW4gJT4lIAogIGZpbHRlcihjb3VudHkgPT0gIkJvb25lIikKI0Jvb25lIENvdW50eSBoYXMgNiBjb29saW5nIGNlbnRlcnMKCmNvb2xpbmdjZW50ZXJzY2xlYW4gJT4lIAogIGZpbHRlcihncmVwbCgic3VuIiwgaG91cnNfb2Zfb3BlcmF0aW9uLCBpZ25vcmUuY2FzZT1UKSkKIzU4IGNlbnRlcnMgYXJlIG9wZW4gb24gU3VuZGF5cwoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGFycmFuZ2UoZGVzYyh2YWx1ZSkpCiNDYWxpZm9ybmlhIGhhZCB0aGUgaGlnaGVzdCBoZWF0LXJlbGF0ZWQgaG9zcGl0YWxpemF0aW9uIHJhdGUgaW4gMjAyMDsgTWlzc291cmkgaGFkIHRoZSBzaXh0aCBoaWdoZXN0IHJhdGUgaW4gMjAxMSBhdCA3LjYuCgpoZWF0aG9zcGl0YWxpemF0aW9ucyAlPiUgCiAgZmlsdGVyKHN0YXRlPT0iTWlzc291cmkiKSAlPiUgCiAgYXJyYW5nZShkZXNjKHZhbHVlKSkKI01pc3NvdXJpIGhhZCBpdHMgaGlnaGVzdCBudW1iZXIgb2YgaGVhdC1yZWxhdGVkIGhvc3BpdGFsaXphdGlvbnMgaW4gMjAxMQoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIHN1bW1hcmlzZShhdmVyYWdlID0gbWVhbih2YWx1ZSkpCiNUaGUgYXZlcmFnZSBwZXJjZW50YWdlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzIGhvc3BpdGFsaXphdGlvbnMgZnJvbSAyMDAwIHRvIDIwMjEgdXNpbmcgYXZhaWxibGUgZGF0YSB3YXMgMi4wMTAxMzMlLgoKaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGdyb3VwX2J5KHN0YXRlKSAlPiUgCiAgc3VtbWFyaXNlKGF2ZXJhZ2UgPSBtZWFuKHZhbHVlKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhhdmVyYWdlKSkKI01pc3NvdXJpIGhhcyB0aGUgc2Vjb25kIGhpZ2hlc3QgcmF0ZSBvZiB0aGUgZGF0YSByZXBvcnRlZC4gCgoKYGBgCgojIyMgU3RvcnkgUGFja2FnZQoKKipJbXBvcnRhbnQgc3RhdGlzdGljcyBhbmQgZGF0YSBhbmFseXNpcyB0byBpbmNsdWRlIGluIHRoZSBzdG9yeToqKgoKSW4gdGhlIGxhc3QgdHdvIGRlY2FkZXMsIE1pc3NvdXJpIHJhbmtzIGluIHRoZSB0b3AgdGVuIG91dCBvZiByZXBvcnRpbmcgc3RhdGVzIGZvciB0aGUgaGlnaGVzdCByYXRlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzZXMgcGVyIDEwMCwwMDAgcGVvcGxlLiBJbiAyMDExLCB0aGUgcmF0ZSBpbiBNaXNzb3VyaSByZWFjaGVkIDcuNiUsIHJhbmtpbmcgaXQgbnVtYmVyIDYgYmVoaW5kIEFyaXpvbmEuCgpNaXNzb3VyaSBjdXJyZW50bHkgcmVwb3J0cyA1MzggY29vbGluZyBjZW50ZXJzLiA1OCBvZiB0aG9zZSBjb29saW5nIGNlbnRlcnMgYXJlIG9wZW4gb24gU3VuZGF5cy4KCioqR3JhcGhzIHRvIGluY2x1ZGUgaW4gdGhlIHN0b3J5OioqCgpgYGB7cn0KZG90bWFwCmBgYAoKYGBge3J9CmludGVyYWN0aXZlZG90bWFwCmBgYAoKYGBge3J9CmJhcl9ncmFwaApgYGAKCmBgYHtyfQpjaGxvcm9fbWFwCmBgYAoKIyMjIE1ldGhvZG9sb2d5OgoKVGhyZWUgZGF0YSBzZXRzIHdlcmUgdXNlZCBhbmQgYW5hbHl6ZWQgaW4gdGhpcyBzdG9yeSBwYWNrYWdlLgoKVGhlIGZpcnN0IGRhdGEgc2V0IGRvY3VtZW50cyB0aGUgbG9jYXRpb25zIG9mIGNvb2xpbmcgY2VudGVycyBpbiB0aGUgc3RhdGUgb2YgTWlzc291cmkuIFRoaXMgZGF0YSBpcyBmcm9tIDIwMjIgYW5kIHdhcyBjb2xsZWN0ZWQgZnJvbSBkYXRhLm1vLmdvdi4gSXQgaXMgcmVwb3J0ZWQgYnkgdGhlIE1pc3NvdXJpIERlcGFydG1lbnQgb2YgSGVhbHRoICYgU2VuaW9yIFNlcnZpY2VzLiBUaGUgZGF0YSBvbmx5IGluY2x1ZGVzIGNvb2xpbmcgY2VudGVycyB0aGF0IGFyZSByZXBvcnRlZCB0byB0aGUgTWlzc291cmkgRGVwYXJ0bWVudCBvZiBIZWFsdGggJiBTZW5pb3IgU2VydmljZXMsIGFuZCB0aGVyZWZvcmUgbWF5IGV4Y2x1ZGUgc29tZSBjb29saW5nIGNlbnRlcnMuCgpUaGUgc2Vjb25kIGRhdGEgc2V0IGRvY3VtZW50cyB0aGUgcGVyY2VudCBvZiBhZ2UtYWRqdXN0ZWQgaGVhdC1yZWxhdGVkIGlsbG5lc3MgaG9zcGl0YWxpemF0aW9ucyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBwZXIgMTAwLDAwMCBwZW9wbGUuIEl0IHdhcyBhY2Nlc3NlZCBmcm9tIHRoZSBDZW50ZXJzIGZvciBEaXNlYXNlIENvbnRyb2wuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgYWxsIHN0YXRlcyByZXBvcnQgZGF0YSBldmVyeSB5ZWFyLiBJbiBteSBhbmFseXNpcywgSSBpbmNsdWRlZCBhbGwgc3RhdGVzJyBkYXRhLiBJbiBjcmVhdGluZyB0aGUgYmFyIGNoYXJ0LCBob3dldmVyLCBJIGluY2x1ZGVkIGZpbHRlcmVkIGZvciBkYXRhIGZyb20gb25seSBNaXNzb3VyaSwgZm9yIGFsbCB5ZWFycyBhdmFpbGFibGUgZnJvbSAyMDAwIHRvIDIwMjEuCgpUaGUgdGhpcmQgZGF0YSBzZXQgZG9jdW1lbnRzIHRoZSBudW1iZXIgb2YgdW5zaGVsdGVyZWQgaW5kaXZpZHVhbHMgZXhwZXJpZW5jaW5nIGhvbWVsZXNzbmVzcyBpbiAyMDE5LCB3aGljaCBpcyB0aGUgbW9zdCByZWNlbnQgZGF0YSBhdmFpbGFibGUgZm9yIGRvd25sb2FkLiBJdCBjb21lcyBmcm9tIHRoZSBNaXNzb3VyaSBCYWxhbmNlIG9mIFN0YXRlIENvbnRpbnVhIG9mIENhcmUsIGFzIHJlcXVpcmVkIGJ5IHRoZSBNaXNzb3VyaSBEZXBhcnRtZW50IG9mIEhlYWx0aCAmIFNlbmlvciBTZXJ2aWNlcy4gU29tZSBjb3VudGllcyBhcmUgbm90IHJlcG9ydGVkIGluIHRoZSBkYXRhLiBJbiB0aGUgY2hhcnQsIHRoZXNlIGNvdW50aWVzIGFyZSBsaXN0ZWQgd2l0aCBkYXRhIGFzICJOL0EiLgoKKkFuaW1hdGlvbiBjb2RlOioKClRoaXMgY29kZSBtYXkgdGFrZSBhIHdoaWxlIHRvIGxvYWQsIGFuZCByZXF1aXJlcyByZW5kZXJpbmcgcGFja2FnZXMgdG8gc2hvdyB0aGUgYW5pbWF0aW9uLgoKYGBge3J9CmFuaW1hdGVkZ3JhcGggPC0gaGVhdGhvc3BpdGFsaXphdGlvbnMgJT4lIAogIGZpbHRlcihzdGF0ZT09Ik1pc3NvdXJpIiB8IHN0YXRlPT0iQXJpem9uYSIpICU+JSAKICBnZ3Bsb3QoYWVzKHg9c3RhdGUsIHk9dmFsdWUsIGZpbGw9c3RhdGUpKSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplID0gNyksIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9NyksIHRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTcpLCBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NykpICsKbGFicyh0aXRsZSA9ICJQZXJjZW50YWdlIG9mIGhlYXQtcmVsYXRlZCBpbGxuZXNzIGhvc3BpdGFsaXphdGlvbnMgaW4gTWlzc291cmkgYW5kIEFyaXpvbmEgcGVyIDEwMGsgcGVvcGxlIDIwMDAtMjAyMCIsIHN1YnRpdGxlID0gIkRhdGEgZnJvbSBDREMiKSArCnlsYWIoIlBlcmNlbnRhZ2Ugb2YgaGVhdCBob3NwaXRhbGl6YXRpb25zIikgKwp4bGFiKCJZZWFyIikKCiBhbmltYXRlZGdyYXBoICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArCiAgdHJhbnNpdGlvbl9zdGF0ZXMoCiAgICB5ZWFyLAogICAgdHJhbnNpdGlvbl9sZW5ndGggPSAyMCwKICAgIHN0YXRlX2xlbmd0aCA9IDEpICsKICBlYXNlX2Flcygnc2luZS1pbi1vdXQnKSArCiAgICAgdHJhbnNpdGlvbl90aW1lKHllYXIpICsKbGFicyh0aXRsZSA9ICJZZWFyOiB7ZnJhbWVfdGltZX0iKQoKCmBgYAo=